@@ -7,12 +7,15 @@ import android.support.v7.widget.GridLayoutManager; |
||
| 7 | 7 |
import android.support.v7.widget.LinearLayoutManager; |
| 8 | 8 |
import android.support.v7.widget.RecyclerView; |
| 9 | 9 |
import android.view.View; |
| 10 |
+import android.widget.Button; |
|
| 10 | 11 |
import android.widget.ImageView; |
| 12 |
+import android.widget.RelativeLayout; |
|
| 11 | 13 |
import android.widget.TextView; |
| 12 | 14 |
import android.widget.Toast; |
| 13 | 15 |
|
| 14 | 16 |
import com.android.common.utils.LogHelper; |
| 15 | 17 |
import com.android.common.utils.NetworkUtil; |
| 18 |
+import com.android.views.loadingdrawable.LoadingView; |
|
| 16 | 19 |
import com.umeng.analytics.MobclickAgent; |
| 17 | 20 |
|
| 18 | 21 |
import java.util.ArrayList; |
@@ -36,6 +39,10 @@ public class MainActivity extends BaseActivity implements MainContract.View {
|
||
| 36 | 39 |
@BindView(R.id.iv_add_session) ImageView addSessionBtn; |
| 37 | 40 |
@BindView(R.id.container_view) View containerView; |
| 38 | 41 |
@BindView(R.id.recycler_view_sessions) RecyclerView sessionsRecyclerView; |
| 42 |
+ @BindView(R.id.sync_time_view) RelativeLayout syncTimeView; |
|
| 43 |
+ @BindView(R.id.loading_gear_view) LoadingView loadingView; |
|
| 44 |
+ @BindView(R.id.tv_sync_time_status) TextView syncStatusTextView; |
|
| 45 |
+ @BindView(R.id.btn_retry_sync) Button retrySyncBtn; |
|
| 39 | 46 |
private SessionRecyclerAdapter adapter; |
| 40 | 47 |
private MainContract.Presenter presenter; |
| 41 | 48 |
private long exitTime; |
@@ -77,6 +84,12 @@ public class MainActivity extends BaseActivity implements MainContract.View {
|
||
| 77 | 84 |
} |
| 78 | 85 |
} |
| 79 | 86 |
|
| 87 |
+ @OnClick(R.id.btn_retry_sync) |
|
| 88 |
+ void retrySync(){
|
|
| 89 |
+ showTimeSyncView(); |
|
| 90 |
+ presenter.resyncTime(); |
|
| 91 |
+ } |
|
| 92 |
+ |
|
| 80 | 93 |
@OnClick(R.id.layout_brief) |
| 81 | 94 |
void jumpToBriefs(){
|
| 82 | 95 |
MobclickAgent.onEvent(this, UmengEvent.home_brief_btn_click); |
@@ -120,8 +133,9 @@ public class MainActivity extends BaseActivity implements MainContract.View {
|
||
| 120 | 133 |
|
| 121 | 134 |
@Override |
| 122 | 135 |
public void showSessionViews() {
|
| 123 |
- noDataLayout.setVisibility(android.view.View.GONE); |
|
| 124 |
- sessionsRecyclerView.setVisibility(android.view.View.VISIBLE); |
|
| 136 |
+ noDataLayout.setVisibility(View.GONE); |
|
| 137 |
+ syncTimeView.setVisibility(View.GONE); |
|
| 138 |
+ sessionsRecyclerView.setVisibility(View.VISIBLE); |
|
| 125 | 139 |
} |
| 126 | 140 |
|
| 127 | 141 |
@Override |
@@ -140,6 +154,23 @@ public class MainActivity extends BaseActivity implements MainContract.View {
|
||
| 140 | 154 |
addSessionBtn.setEnabled(isEnabled); |
| 141 | 155 |
} |
| 142 | 156 |
|
| 157 |
+ @Override |
|
| 158 |
+ public void showTimeSyncView() {
|
|
| 159 |
+ sessionsRecyclerView.setVisibility(View.GONE); |
|
| 160 |
+ syncTimeView.setVisibility(View.VISIBLE); |
|
| 161 |
+ loadingView.setVisibility(View.VISIBLE); |
|
| 162 |
+ syncStatusTextView.setText(R.string.time_syncing); |
|
| 163 |
+ } |
|
| 164 |
+ |
|
| 165 |
+ @Override |
|
| 166 |
+ public void showRetrySyncView(int strId) {
|
|
| 167 |
+ retrySyncBtn.setVisibility(View.VISIBLE); |
|
| 168 |
+ loadingView.setVisibility(View.INVISIBLE); |
|
| 169 |
+ if(strId!=0){
|
|
| 170 |
+ syncStatusTextView.setText(strId); |
|
| 171 |
+ } |
|
| 172 |
+ |
|
| 173 |
+ } |
|
| 143 | 174 |
|
| 144 | 175 |
private void jumpToSelectedSession(SessionBean sessionBean) {
|
| 145 | 176 |
Intent intent = new Intent(this, SessionActivity.class); |
@@ -18,11 +18,13 @@ public class MainContract {
|
||
| 18 | 18 |
void updateSessionUploadViewAt(int position); |
| 19 | 19 |
void refreshSessionViews(ArrayList<SessionBean> sessionList); |
| 20 | 20 |
void setNewSessionBtnEnabled(boolean isEnabled); |
| 21 |
+ void showTimeSyncView(); |
|
| 22 |
+ void showRetrySyncView(int strId); |
|
| 21 | 23 |
} |
| 22 | 24 |
|
| 23 | 25 |
interface Presenter extends BasePresenter{
|
| 24 | 26 |
SessionBean createNewSession(); |
| 25 |
- |
|
| 27 |
+ void resyncTime(); |
|
| 26 | 28 |
} |
| 27 | 29 |
|
| 28 | 30 |
} |
@@ -103,6 +103,7 @@ class MainPresenter implements MainContract.Presenter,BaseInteractor.InteractorL |
||
| 103 | 103 |
view.showBoxDisconnectedView(); |
| 104 | 104 |
} |
| 105 | 105 |
view.setNewSessionBtnEnabled(false); |
| 106 |
+ view.showTimeSyncView(); |
|
| 106 | 107 |
if(sessionIds==null|| sessionIds.size()<20){
|
| 107 | 108 |
fetchSessionIdsInteractor.startJob(); |
| 108 | 109 |
} |
@@ -136,6 +137,7 @@ class MainPresenter implements MainContract.Presenter,BaseInteractor.InteractorL |
||
| 136 | 137 |
if(sessionIds==null|sessionIds.size()<20){
|
| 137 | 138 |
return; |
| 138 | 139 |
} |
| 140 |
+ |
|
| 139 | 141 |
view.setNewSessionBtnEnabled(true); |
| 140 | 142 |
if(sessionList.size()==0){
|
| 141 | 143 |
view.showEmptyView(); |
@@ -169,6 +171,14 @@ class MainPresenter implements MainContract.Presenter,BaseInteractor.InteractorL |
||
| 169 | 171 |
return sessionBean; |
| 170 | 172 |
} |
| 171 | 173 |
|
| 174 |
+ @Override |
|
| 175 |
+ public void resyncTime() {
|
|
| 176 |
+ if(syncTimeInteractor!=null){
|
|
| 177 |
+ syncTimeInteractor.cancelJob(); |
|
| 178 |
+ syncTimeInteractor.startJob(); |
|
| 179 |
+ } |
|
| 180 |
+ } |
|
| 181 |
+ |
|
| 172 | 182 |
private long getSessionDateInLongFormat(){
|
| 173 | 183 |
SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
|
| 174 | 184 |
String dateStr = format.format(new Date()); |
@@ -274,7 +284,7 @@ class MainPresenter implements MainContract.Presenter,BaseInteractor.InteractorL |
||
| 274 | 284 |
onDataReady(); |
| 275 | 285 |
}else{
|
| 276 | 286 |
if(strId!=0){
|
| 277 |
- view.showSnackBar(strId); |
|
| 287 |
+ view.showRetrySyncView(strId); |
|
| 278 | 288 |
} |
| 279 | 289 |
} |
| 280 | 290 |
} |
@@ -0,0 +1,12 @@ |
||
| 1 |
+<?xml version="1.0" encoding="utf-8"?> |
|
| 2 |
+<shape xmlns:android="http://schemas.android.com/apk/res/android" |
|
| 3 |
+ android:shape="rectangle" > |
|
| 4 |
+ |
|
| 5 |
+ <solid android:color="@color/transparent" /> |
|
| 6 |
+ |
|
| 7 |
+ <corners |
|
| 8 |
+ android:radius="6dp"/> |
|
| 9 |
+ |
|
| 10 |
+ <stroke android:width="1dp" android:color="@color/white"/> |
|
| 11 |
+ |
|
| 12 |
+</shape> |
@@ -1,5 +1,6 @@ |
||
| 1 | 1 |
<?xml version="1.0" encoding="utf-8"?> |
| 2 | 2 |
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" |
| 3 |
+ xmlns:app="http://schemas.android.com/apk/res-auto" |
|
| 3 | 4 |
android:id="@+id/container_view" |
| 4 | 5 |
android:layout_width="match_parent" |
| 5 | 6 |
android:layout_height="match_parent" |
@@ -54,6 +55,46 @@ |
||
| 54 | 55 |
android:layout_centerInParent="true" |
| 55 | 56 |
android:src="@drawable/no_photo_tip" /> |
| 56 | 57 |
|
| 58 |
+ <RelativeLayout |
|
| 59 |
+ android:id="@+id/sync_time_view" |
|
| 60 |
+ android:layout_width="match_parent" |
|
| 61 |
+ android:layout_height="match_parent" |
|
| 62 |
+ android:background="@color/half_transparent"> |
|
| 63 |
+ |
|
| 64 |
+ <com.android.views.loadingdrawable.LoadingView |
|
| 65 |
+ android:id="@+id/loading_gear_view" |
|
| 66 |
+ android:layout_width="180dp" |
|
| 67 |
+ android:layout_height="180dp" |
|
| 68 |
+ android:layout_centerInParent="true" |
|
| 69 |
+ app:loading_renderer="GearLoadingRenderer"/> |
|
| 70 |
+ |
|
| 71 |
+ <TextView |
|
| 72 |
+ android:id="@+id/tv_sync_time_status" |
|
| 73 |
+ android:layout_width="wrap_content" |
|
| 74 |
+ android:layout_height="wrap_content" |
|
| 75 |
+ android:textSize="16sp" |
|
| 76 |
+ android:text="@string/time_syncing" |
|
| 77 |
+ android:layout_below="@id/loading_gear_view" |
|
| 78 |
+ android:layout_marginTop="10dp" |
|
| 79 |
+ android:layout_centerHorizontal="true" |
|
| 80 |
+ android:textColor="@color/white"/> |
|
| 81 |
+ |
|
| 82 |
+ <Button |
|
| 83 |
+ android:id="@+id/btn_retry_sync" |
|
| 84 |
+ android:layout_width="140dp" |
|
| 85 |
+ android:layout_height="40dp" |
|
| 86 |
+ android:layout_centerHorizontal="true" |
|
| 87 |
+ android:layout_below="@id/tv_sync_time_status" |
|
| 88 |
+ android:layout_marginTop="10dp" |
|
| 89 |
+ android:background="@drawable/retry_sync_btn_rounded_rect_bg" |
|
| 90 |
+ android:gravity="center" |
|
| 91 |
+ android:text="@string/time_sync_retry" |
|
| 92 |
+ android:textColor="@color/white" |
|
| 93 |
+ android:visibility="gone" |
|
| 94 |
+ android:textSize="18sp" /> |
|
| 95 |
+ </RelativeLayout> |
|
| 96 |
+ |
|
| 97 |
+ |
|
| 57 | 98 |
<android.support.v7.widget.RecyclerView |
| 58 | 99 |
android:id="@+id/recycler_view_sessions" |
| 59 | 100 |
android:layout_width="match_parent" |
@@ -174,7 +174,11 @@ |
||
| 174 | 174 |
|
| 175 | 175 |
<string name="upload_settings">上传管理</string> |
| 176 | 176 |
|
| 177 |
- <string name="sync_time_server_error">时间同步出错,请检查网络连接后退出重试</string> |
|
| 178 |
- <string name="sync_time_box_error">时间同步出错,请检查盒子是否打开后退出重试</string> |
|
| 177 |
+ <string name="sync_time_server_error">时间同步出错,请检查网络连接</string> |
|
| 178 |
+ <string name="sync_time_box_error">时间同步出错,请检查盒子是否打开</string> |
|
| 179 |
+ |
|
| 180 |
+ <string name="time_syncing">正在同步时间...</string> |
|
| 181 |
+ |
|
| 182 |
+ <string name="time_sync_retry">重新同步</string> |
|
| 179 | 183 |
|
| 180 | 184 |
</resources> |
@@ -0,0 +1,11 @@ |
||
| 1 |
+package com.android.views.loadingdrawable; |
|
| 2 |
+ |
|
| 3 |
+import android.content.Context; |
|
| 4 |
+ |
|
| 5 |
+public class DensityUtil {
|
|
| 6 |
+ |
|
| 7 |
+ public static float dip2px(Context context, float dpValue) {
|
|
| 8 |
+ float scale = context.getResources().getDisplayMetrics().density; |
|
| 9 |
+ return dpValue * scale; |
|
| 10 |
+ } |
|
| 11 |
+} |
@@ -0,0 +1,78 @@ |
||
| 1 |
+package com.android.views.loadingdrawable; |
|
| 2 |
+ |
|
| 3 |
+import android.content.Context; |
|
| 4 |
+import android.content.res.TypedArray; |
|
| 5 |
+import android.util.AttributeSet; |
|
| 6 |
+import android.view.View; |
|
| 7 |
+import android.widget.ImageView; |
|
| 8 |
+ |
|
| 9 |
+import com.android.views.R; |
|
| 10 |
+import com.android.views.loadingdrawable.render.LoadingDrawable; |
|
| 11 |
+import com.android.views.loadingdrawable.render.LoadingRenderer; |
|
| 12 |
+import com.android.views.loadingdrawable.render.LoadingRendererFactory; |
|
| 13 |
+ |
|
| 14 |
+public class LoadingView extends ImageView {
|
|
| 15 |
+ private LoadingDrawable mLoadingDrawable; |
|
| 16 |
+ |
|
| 17 |
+ public LoadingView(Context context) {
|
|
| 18 |
+ super(context); |
|
| 19 |
+ } |
|
| 20 |
+ |
|
| 21 |
+ public LoadingView(Context context, AttributeSet attrs) {
|
|
| 22 |
+ super(context, attrs); |
|
| 23 |
+ initAttrs(context, attrs); |
|
| 24 |
+ } |
|
| 25 |
+ |
|
| 26 |
+ private void initAttrs(Context context, AttributeSet attrs) {
|
|
| 27 |
+ try {
|
|
| 28 |
+ TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.LoadingView); |
|
| 29 |
+ int loadingRendererId = ta.getInt(R.styleable.LoadingView_loading_renderer, 0); |
|
| 30 |
+ LoadingRenderer loadingRenderer = LoadingRendererFactory.createLoadingRenderer(context, loadingRendererId); |
|
| 31 |
+ setLoadingRenderer(loadingRenderer); |
|
| 32 |
+ ta.recycle(); |
|
| 33 |
+ } catch (Exception e) {
|
|
| 34 |
+ e.printStackTrace(); |
|
| 35 |
+ } |
|
| 36 |
+ } |
|
| 37 |
+ |
|
| 38 |
+ public void setLoadingRenderer(LoadingRenderer loadingRenderer) {
|
|
| 39 |
+ mLoadingDrawable = new LoadingDrawable(loadingRenderer); |
|
| 40 |
+ setImageDrawable(mLoadingDrawable); |
|
| 41 |
+ } |
|
| 42 |
+ |
|
| 43 |
+ @Override |
|
| 44 |
+ protected void onAttachedToWindow() {
|
|
| 45 |
+ super.onAttachedToWindow(); |
|
| 46 |
+ startAnimation(); |
|
| 47 |
+ } |
|
| 48 |
+ |
|
| 49 |
+ @Override |
|
| 50 |
+ protected void onDetachedFromWindow() {
|
|
| 51 |
+ super.onDetachedFromWindow(); |
|
| 52 |
+ stopAnimation(); |
|
| 53 |
+ } |
|
| 54 |
+ |
|
| 55 |
+ @Override |
|
| 56 |
+ protected void onVisibilityChanged(View changedView, int visibility) {
|
|
| 57 |
+ super.onVisibilityChanged(changedView, visibility); |
|
| 58 |
+ |
|
| 59 |
+ final boolean visible = visibility == VISIBLE && getVisibility() == VISIBLE; |
|
| 60 |
+ if (visible) {
|
|
| 61 |
+ startAnimation(); |
|
| 62 |
+ } else {
|
|
| 63 |
+ stopAnimation(); |
|
| 64 |
+ } |
|
| 65 |
+ } |
|
| 66 |
+ |
|
| 67 |
+ private void startAnimation() {
|
|
| 68 |
+ if (mLoadingDrawable != null) {
|
|
| 69 |
+ mLoadingDrawable.start(); |
|
| 70 |
+ } |
|
| 71 |
+ } |
|
| 72 |
+ |
|
| 73 |
+ private void stopAnimation() {
|
|
| 74 |
+ if (mLoadingDrawable != null) {
|
|
| 75 |
+ mLoadingDrawable.stop(); |
|
| 76 |
+ } |
|
| 77 |
+ } |
|
| 78 |
+} |
@@ -0,0 +1,87 @@ |
||
| 1 |
+package com.android.views.loadingdrawable.render; |
|
| 2 |
+ |
|
| 3 |
+import android.graphics.Canvas; |
|
| 4 |
+import android.graphics.ColorFilter; |
|
| 5 |
+import android.graphics.PixelFormat; |
|
| 6 |
+import android.graphics.Rect; |
|
| 7 |
+import android.graphics.drawable.Animatable; |
|
| 8 |
+import android.graphics.drawable.Drawable; |
|
| 9 |
+ |
|
| 10 |
+public class LoadingDrawable extends Drawable implements Animatable {
|
|
| 11 |
+ private final LoadingRenderer mLoadingRender; |
|
| 12 |
+ |
|
| 13 |
+ private final Callback mCallback = new Callback() {
|
|
| 14 |
+ @Override |
|
| 15 |
+ public void invalidateDrawable(Drawable d) {
|
|
| 16 |
+ invalidateSelf(); |
|
| 17 |
+ } |
|
| 18 |
+ |
|
| 19 |
+ @Override |
|
| 20 |
+ public void scheduleDrawable(Drawable d, Runnable what, long when) {
|
|
| 21 |
+ scheduleSelf(what, when); |
|
| 22 |
+ } |
|
| 23 |
+ |
|
| 24 |
+ @Override |
|
| 25 |
+ public void unscheduleDrawable(Drawable d, Runnable what) {
|
|
| 26 |
+ unscheduleSelf(what); |
|
| 27 |
+ } |
|
| 28 |
+ }; |
|
| 29 |
+ |
|
| 30 |
+ public LoadingDrawable(LoadingRenderer loadingRender) {
|
|
| 31 |
+ this.mLoadingRender = loadingRender; |
|
| 32 |
+ this.mLoadingRender.setCallback(mCallback); |
|
| 33 |
+ } |
|
| 34 |
+ |
|
| 35 |
+ @Override |
|
| 36 |
+ protected void onBoundsChange(Rect bounds) {
|
|
| 37 |
+ super.onBoundsChange(bounds); |
|
| 38 |
+ this.mLoadingRender.setBounds(bounds); |
|
| 39 |
+ } |
|
| 40 |
+ |
|
| 41 |
+ @Override |
|
| 42 |
+ public void draw(Canvas canvas) {
|
|
| 43 |
+ if (!getBounds().isEmpty()) {
|
|
| 44 |
+ this.mLoadingRender.draw(canvas); |
|
| 45 |
+ } |
|
| 46 |
+ } |
|
| 47 |
+ |
|
| 48 |
+ @Override |
|
| 49 |
+ public void setAlpha(int alpha) {
|
|
| 50 |
+ this.mLoadingRender.setAlpha(alpha); |
|
| 51 |
+ } |
|
| 52 |
+ |
|
| 53 |
+ @Override |
|
| 54 |
+ public void setColorFilter(ColorFilter cf) {
|
|
| 55 |
+ this.mLoadingRender.setColorFilter(cf); |
|
| 56 |
+ } |
|
| 57 |
+ |
|
| 58 |
+ @Override |
|
| 59 |
+ public int getOpacity() {
|
|
| 60 |
+ return PixelFormat.TRANSLUCENT; |
|
| 61 |
+ } |
|
| 62 |
+ |
|
| 63 |
+ @Override |
|
| 64 |
+ public void start() {
|
|
| 65 |
+ this.mLoadingRender.start(); |
|
| 66 |
+ } |
|
| 67 |
+ |
|
| 68 |
+ @Override |
|
| 69 |
+ public void stop() {
|
|
| 70 |
+ this.mLoadingRender.stop(); |
|
| 71 |
+ } |
|
| 72 |
+ |
|
| 73 |
+ @Override |
|
| 74 |
+ public boolean isRunning() {
|
|
| 75 |
+ return this.mLoadingRender.isRunning(); |
|
| 76 |
+ } |
|
| 77 |
+ |
|
| 78 |
+ @Override |
|
| 79 |
+ public int getIntrinsicHeight() {
|
|
| 80 |
+ return (int) this.mLoadingRender.mHeight; |
|
| 81 |
+ } |
|
| 82 |
+ |
|
| 83 |
+ @Override |
|
| 84 |
+ public int getIntrinsicWidth() {
|
|
| 85 |
+ return (int) this.mLoadingRender.mWidth; |
|
| 86 |
+ } |
|
| 87 |
+} |
@@ -0,0 +1,120 @@ |
||
| 1 |
+package com.android.views.loadingdrawable.render; |
|
| 2 |
+ |
|
| 3 |
+import android.animation.Animator; |
|
| 4 |
+import android.animation.ValueAnimator; |
|
| 5 |
+import android.content.Context; |
|
| 6 |
+import android.graphics.Canvas; |
|
| 7 |
+import android.graphics.ColorFilter; |
|
| 8 |
+import android.graphics.Rect; |
|
| 9 |
+import android.graphics.drawable.Drawable; |
|
| 10 |
+import android.view.animation.Animation; |
|
| 11 |
+import android.view.animation.LinearInterpolator; |
|
| 12 |
+ |
|
| 13 |
+import com.android.views.loadingdrawable.DensityUtil; |
|
| 14 |
+ |
|
| 15 |
+public abstract class LoadingRenderer {
|
|
| 16 |
+ private static final long ANIMATION_DURATION = 1333; |
|
| 17 |
+ private static final float DEFAULT_SIZE = 56.0f; |
|
| 18 |
+ |
|
| 19 |
+ private final ValueAnimator.AnimatorUpdateListener mAnimatorUpdateListener |
|
| 20 |
+ = new ValueAnimator.AnimatorUpdateListener() {
|
|
| 21 |
+ @Override |
|
| 22 |
+ public void onAnimationUpdate(ValueAnimator animation) {
|
|
| 23 |
+ computeRender((float) animation.getAnimatedValue()); |
|
| 24 |
+ invalidateSelf(); |
|
| 25 |
+ } |
|
| 26 |
+ }; |
|
| 27 |
+ |
|
| 28 |
+ /** |
|
| 29 |
+ * Whenever {@link LoadingDrawable} boundary changes mBounds will be updated.
|
|
| 30 |
+ * More details you can see {@link LoadingDrawable#onBoundsChange(Rect)}
|
|
| 31 |
+ */ |
|
| 32 |
+ protected final Rect mBounds = new Rect(); |
|
| 33 |
+ |
|
| 34 |
+ private Drawable.Callback mCallback; |
|
| 35 |
+ private ValueAnimator mRenderAnimator; |
|
| 36 |
+ |
|
| 37 |
+ protected long mDuration; |
|
| 38 |
+ |
|
| 39 |
+ protected float mWidth; |
|
| 40 |
+ protected float mHeight; |
|
| 41 |
+ |
|
| 42 |
+ public LoadingRenderer(Context context) {
|
|
| 43 |
+ initParams(context); |
|
| 44 |
+ setupAnimators(); |
|
| 45 |
+ } |
|
| 46 |
+ |
|
| 47 |
+ @Deprecated |
|
| 48 |
+ protected void draw(Canvas canvas, Rect bounds) {
|
|
| 49 |
+ } |
|
| 50 |
+ |
|
| 51 |
+ protected void draw(Canvas canvas) {
|
|
| 52 |
+ draw(canvas, mBounds); |
|
| 53 |
+ } |
|
| 54 |
+ |
|
| 55 |
+ protected abstract void computeRender(float renderProgress); |
|
| 56 |
+ |
|
| 57 |
+ protected abstract void setAlpha(int alpha); |
|
| 58 |
+ |
|
| 59 |
+ protected abstract void setColorFilter(ColorFilter cf); |
|
| 60 |
+ |
|
| 61 |
+ protected abstract void reset(); |
|
| 62 |
+ |
|
| 63 |
+ protected void addRenderListener(Animator.AnimatorListener animatorListener) {
|
|
| 64 |
+ mRenderAnimator.addListener(animatorListener); |
|
| 65 |
+ } |
|
| 66 |
+ |
|
| 67 |
+ void start() {
|
|
| 68 |
+ reset(); |
|
| 69 |
+ mRenderAnimator.addUpdateListener(mAnimatorUpdateListener); |
|
| 70 |
+ |
|
| 71 |
+ mRenderAnimator.setRepeatCount(ValueAnimator.INFINITE); |
|
| 72 |
+ mRenderAnimator.setDuration(mDuration); |
|
| 73 |
+ mRenderAnimator.start(); |
|
| 74 |
+ } |
|
| 75 |
+ |
|
| 76 |
+ void stop() {
|
|
| 77 |
+ // if I just call mRenderAnimator.end(), |
|
| 78 |
+ // it will always call the method onAnimationUpdate(ValueAnimator animation) |
|
| 79 |
+ // why ? if you know why please send email to me (dinus_developer@163.com) |
|
| 80 |
+ mRenderAnimator.removeUpdateListener(mAnimatorUpdateListener); |
|
| 81 |
+ |
|
| 82 |
+ mRenderAnimator.setRepeatCount(0); |
|
| 83 |
+ mRenderAnimator.setDuration(0); |
|
| 84 |
+ mRenderAnimator.end(); |
|
| 85 |
+ } |
|
| 86 |
+ |
|
| 87 |
+ boolean isRunning() {
|
|
| 88 |
+ return mRenderAnimator.isRunning(); |
|
| 89 |
+ } |
|
| 90 |
+ |
|
| 91 |
+ void setCallback(Drawable.Callback callback) {
|
|
| 92 |
+ this.mCallback = callback; |
|
| 93 |
+ } |
|
| 94 |
+ |
|
| 95 |
+ void setBounds(Rect bounds) {
|
|
| 96 |
+ mBounds.set(bounds); |
|
| 97 |
+ } |
|
| 98 |
+ |
|
| 99 |
+ private void initParams(Context context) {
|
|
| 100 |
+ mWidth = DensityUtil.dip2px(context, DEFAULT_SIZE); |
|
| 101 |
+ mHeight = DensityUtil.dip2px(context, DEFAULT_SIZE); |
|
| 102 |
+ |
|
| 103 |
+ mDuration = ANIMATION_DURATION; |
|
| 104 |
+ } |
|
| 105 |
+ |
|
| 106 |
+ private void setupAnimators() {
|
|
| 107 |
+ mRenderAnimator = ValueAnimator.ofFloat(0.0f, 1.0f); |
|
| 108 |
+ mRenderAnimator.setRepeatCount(Animation.INFINITE); |
|
| 109 |
+ mRenderAnimator.setRepeatMode(Animation.RESTART); |
|
| 110 |
+ mRenderAnimator.setDuration(mDuration); |
|
| 111 |
+ //fuck you! the default interpolator is AccelerateDecelerateInterpolator |
|
| 112 |
+ mRenderAnimator.setInterpolator(new LinearInterpolator()); |
|
| 113 |
+ mRenderAnimator.addUpdateListener(mAnimatorUpdateListener); |
|
| 114 |
+ } |
|
| 115 |
+ |
|
| 116 |
+ private void invalidateSelf() {
|
|
| 117 |
+ mCallback.invalidateDrawable(null); |
|
| 118 |
+ } |
|
| 119 |
+ |
|
| 120 |
+} |
@@ -0,0 +1,36 @@ |
||
| 1 |
+package com.android.views.loadingdrawable.render; |
|
| 2 |
+ |
|
| 3 |
+import android.content.Context; |
|
| 4 |
+import android.util.SparseArray; |
|
| 5 |
+ |
|
| 6 |
+import com.android.views.loadingdrawable.render.circle.rotate.GearLoadingRenderer; |
|
| 7 |
+ |
|
| 8 |
+import java.lang.reflect.Constructor; |
|
| 9 |
+ |
|
| 10 |
+public final class LoadingRendererFactory {
|
|
| 11 |
+ private static final SparseArray<Class<? extends LoadingRenderer>> LOADING_RENDERERS = new SparseArray<>(); |
|
| 12 |
+ |
|
| 13 |
+ static {
|
|
| 14 |
+ LOADING_RENDERERS.put(3, GearLoadingRenderer.class); |
|
| 15 |
+ |
|
| 16 |
+ } |
|
| 17 |
+ |
|
| 18 |
+ private LoadingRendererFactory() {
|
|
| 19 |
+ } |
|
| 20 |
+ |
|
| 21 |
+ public static LoadingRenderer createLoadingRenderer(Context context, int loadingRendererId) throws Exception {
|
|
| 22 |
+ Class<?> loadingRendererClazz = LOADING_RENDERERS.get(loadingRendererId); |
|
| 23 |
+ Constructor<?>[] constructors = loadingRendererClazz.getDeclaredConstructors(); |
|
| 24 |
+ for (Constructor<?> constructor : constructors) {
|
|
| 25 |
+ Class<?>[] parameterTypes = constructor.getParameterTypes(); |
|
| 26 |
+ if (parameterTypes != null |
|
| 27 |
+ && parameterTypes.length == 1 |
|
| 28 |
+ && parameterTypes[0].equals(Context.class)) {
|
|
| 29 |
+ constructor.setAccessible(true); |
|
| 30 |
+ return (LoadingRenderer) constructor.newInstance(context); |
|
| 31 |
+ } |
|
| 32 |
+ } |
|
| 33 |
+ |
|
| 34 |
+ throw new InstantiationException(); |
|
| 35 |
+ } |
|
| 36 |
+} |
@@ -0,0 +1,287 @@ |
||
| 1 |
+package com.android.views.loadingdrawable.render.circle.rotate; |
|
| 2 |
+ |
|
| 3 |
+import android.animation.Animator; |
|
| 4 |
+import android.animation.AnimatorListenerAdapter; |
|
| 5 |
+import android.content.Context; |
|
| 6 |
+import android.graphics.Canvas; |
|
| 7 |
+import android.graphics.Color; |
|
| 8 |
+import android.graphics.ColorFilter; |
|
| 9 |
+import android.graphics.Paint; |
|
| 10 |
+import android.graphics.RectF; |
|
| 11 |
+import android.support.annotation.IntRange; |
|
| 12 |
+import android.view.animation.AccelerateInterpolator; |
|
| 13 |
+import android.view.animation.DecelerateInterpolator; |
|
| 14 |
+import android.view.animation.Interpolator; |
|
| 15 |
+ |
|
| 16 |
+import com.android.views.loadingdrawable.DensityUtil; |
|
| 17 |
+import com.android.views.loadingdrawable.render.LoadingRenderer; |
|
| 18 |
+ |
|
| 19 |
+public class GearLoadingRenderer extends LoadingRenderer {
|
|
| 20 |
+ private static final Interpolator ACCELERATE_INTERPOLATOR = new AccelerateInterpolator(); |
|
| 21 |
+ private static final Interpolator DECELERATE_INTERPOLATOR = new DecelerateInterpolator(); |
|
| 22 |
+ |
|
| 23 |
+ private static final int GEAR_COUNT = 4; |
|
| 24 |
+ private static final int NUM_POINTS = 3; |
|
| 25 |
+ private static final int MAX_ALPHA = 255; |
|
| 26 |
+ private static final int DEGREE_360 = 360; |
|
| 27 |
+ |
|
| 28 |
+ private static final int DEFAULT_GEAR_SWIPE_DEGREES = 60; |
|
| 29 |
+ |
|
| 30 |
+ private static final float FULL_GROUP_ROTATION = 3.0f * DEGREE_360; |
|
| 31 |
+ |
|
| 32 |
+ private static final float START_SCALE_DURATION_OFFSET = 0.3f; |
|
| 33 |
+ private static final float START_TRIM_DURATION_OFFSET = 0.5f; |
|
| 34 |
+ private static final float END_TRIM_DURATION_OFFSET = 0.7f; |
|
| 35 |
+ private static final float END_SCALE_DURATION_OFFSET = 1.0f; |
|
| 36 |
+ |
|
| 37 |
+ private static final float DEFAULT_CENTER_RADIUS = 12.5f; |
|
| 38 |
+ private static final float DEFAULT_STROKE_WIDTH = 2.5f; |
|
| 39 |
+ |
|
| 40 |
+ private static final int DEFAULT_COLOR = Color.WHITE; |
|
| 41 |
+ |
|
| 42 |
+ private final Paint mPaint = new Paint(); |
|
| 43 |
+ private final RectF mTempBounds = new RectF(); |
|
| 44 |
+ |
|
| 45 |
+ private final Animator.AnimatorListener mAnimatorListener = new AnimatorListenerAdapter() {
|
|
| 46 |
+ @Override |
|
| 47 |
+ public void onAnimationRepeat(Animator animator) {
|
|
| 48 |
+ super.onAnimationRepeat(animator); |
|
| 49 |
+ storeOriginals(); |
|
| 50 |
+ |
|
| 51 |
+ mStartDegrees = mEndDegrees; |
|
| 52 |
+ mRotationCount = (mRotationCount + 1) % NUM_POINTS; |
|
| 53 |
+ } |
|
| 54 |
+ |
|
| 55 |
+ @Override |
|
| 56 |
+ public void onAnimationStart(Animator animation) {
|
|
| 57 |
+ super.onAnimationStart(animation); |
|
| 58 |
+ mRotationCount = 0; |
|
| 59 |
+ } |
|
| 60 |
+ }; |
|
| 61 |
+ |
|
| 62 |
+ private int mColor; |
|
| 63 |
+ |
|
| 64 |
+ private int mGearCount; |
|
| 65 |
+ private int mGearSwipeDegrees; |
|
| 66 |
+ |
|
| 67 |
+ private float mStrokeInset; |
|
| 68 |
+ |
|
| 69 |
+ private float mRotationCount; |
|
| 70 |
+ private float mGroupRotation; |
|
| 71 |
+ |
|
| 72 |
+ private float mScale; |
|
| 73 |
+ private float mEndDegrees; |
|
| 74 |
+ private float mStartDegrees; |
|
| 75 |
+ private float mSwipeDegrees; |
|
| 76 |
+ private float mOriginEndDegrees; |
|
| 77 |
+ private float mOriginStartDegrees; |
|
| 78 |
+ |
|
| 79 |
+ private float mStrokeWidth; |
|
| 80 |
+ private float mCenterRadius; |
|
| 81 |
+ |
|
| 82 |
+ private GearLoadingRenderer(Context context) {
|
|
| 83 |
+ super(context); |
|
| 84 |
+ |
|
| 85 |
+ init(context); |
|
| 86 |
+ setupPaint(); |
|
| 87 |
+ addRenderListener(mAnimatorListener); |
|
| 88 |
+ } |
|
| 89 |
+ |
|
| 90 |
+ private void init(Context context) {
|
|
| 91 |
+ mStrokeWidth = DensityUtil.dip2px(context, DEFAULT_STROKE_WIDTH); |
|
| 92 |
+ mCenterRadius = DensityUtil.dip2px(context, DEFAULT_CENTER_RADIUS); |
|
| 93 |
+ |
|
| 94 |
+ mColor = DEFAULT_COLOR; |
|
| 95 |
+ |
|
| 96 |
+ mGearCount = GEAR_COUNT; |
|
| 97 |
+ mGearSwipeDegrees = DEFAULT_GEAR_SWIPE_DEGREES; |
|
| 98 |
+ } |
|
| 99 |
+ |
|
| 100 |
+ private void setupPaint() {
|
|
| 101 |
+ mPaint.setAntiAlias(true); |
|
| 102 |
+ mPaint.setStrokeWidth(mStrokeWidth); |
|
| 103 |
+ mPaint.setStyle(Paint.Style.STROKE); |
|
| 104 |
+ mPaint.setStrokeCap(Paint.Cap.ROUND); |
|
| 105 |
+ |
|
| 106 |
+ initStrokeInset(mWidth, mHeight); |
|
| 107 |
+ } |
|
| 108 |
+ |
|
| 109 |
+ @Override |
|
| 110 |
+ protected void draw(Canvas canvas) {
|
|
| 111 |
+ int saveCount = canvas.save(); |
|
| 112 |
+ |
|
| 113 |
+ mTempBounds.set(mBounds); |
|
| 114 |
+ mTempBounds.inset(mStrokeInset, mStrokeInset); |
|
| 115 |
+ mTempBounds.inset(mTempBounds.width() * (1.0f - mScale) / 2.0f, mTempBounds.width() * (1.0f - mScale) / 2.0f); |
|
| 116 |
+ |
|
| 117 |
+ canvas.rotate(mGroupRotation, mTempBounds.centerX(), mTempBounds.centerY()); |
|
| 118 |
+ |
|
| 119 |
+ mPaint.setColor(mColor); |
|
| 120 |
+ mPaint.setAlpha((int) (MAX_ALPHA * mScale)); |
|
| 121 |
+ mPaint.setStrokeWidth(mStrokeWidth * mScale); |
|
| 122 |
+ |
|
| 123 |
+ if (mSwipeDegrees != 0) {
|
|
| 124 |
+ for (int i = 0; i < mGearCount; i++) {
|
|
| 125 |
+ canvas.drawArc(mTempBounds, mStartDegrees + DEGREE_360 / mGearCount * i, mSwipeDegrees, false, mPaint); |
|
| 126 |
+ } |
|
| 127 |
+ } |
|
| 128 |
+ |
|
| 129 |
+ canvas.restoreToCount(saveCount); |
|
| 130 |
+ } |
|
| 131 |
+ |
|
| 132 |
+ @Override |
|
| 133 |
+ protected void computeRender(float renderProgress) {
|
|
| 134 |
+ // Scaling up the start size only occurs in the first 20% of a single ring animation |
|
| 135 |
+ if (renderProgress <= START_SCALE_DURATION_OFFSET) {
|
|
| 136 |
+ float startScaleProgress = (renderProgress) / START_SCALE_DURATION_OFFSET; |
|
| 137 |
+ mScale = DECELERATE_INTERPOLATOR.getInterpolation(startScaleProgress); |
|
| 138 |
+ } |
|
| 139 |
+ |
|
| 140 |
+ // Moving the start trim only occurs between 20% to 50% of a single ring animation |
|
| 141 |
+ if (renderProgress <= START_TRIM_DURATION_OFFSET && renderProgress > START_SCALE_DURATION_OFFSET) {
|
|
| 142 |
+ float startTrimProgress = (renderProgress - START_SCALE_DURATION_OFFSET) / (START_TRIM_DURATION_OFFSET - START_SCALE_DURATION_OFFSET); |
|
| 143 |
+ mStartDegrees = mOriginStartDegrees + mGearSwipeDegrees * startTrimProgress; |
|
| 144 |
+ } |
|
| 145 |
+ |
|
| 146 |
+ // Moving the end trim starts between 50% to 80% of a single ring animation |
|
| 147 |
+ if (renderProgress <= END_TRIM_DURATION_OFFSET && renderProgress > START_TRIM_DURATION_OFFSET) {
|
|
| 148 |
+ float endTrimProgress = (renderProgress - START_TRIM_DURATION_OFFSET) / (END_TRIM_DURATION_OFFSET - START_TRIM_DURATION_OFFSET); |
|
| 149 |
+ mEndDegrees = mOriginEndDegrees + mGearSwipeDegrees * endTrimProgress; |
|
| 150 |
+ } |
|
| 151 |
+ |
|
| 152 |
+ // Scaling down the end size starts after 80% of a single ring animation |
|
| 153 |
+ if (renderProgress > END_TRIM_DURATION_OFFSET) {
|
|
| 154 |
+ float endScaleProgress = (renderProgress - END_TRIM_DURATION_OFFSET) / (END_SCALE_DURATION_OFFSET - END_TRIM_DURATION_OFFSET); |
|
| 155 |
+ mScale = 1.0f - ACCELERATE_INTERPOLATOR.getInterpolation(endScaleProgress); |
|
| 156 |
+ } |
|
| 157 |
+ |
|
| 158 |
+ if (renderProgress <= END_TRIM_DURATION_OFFSET && renderProgress > START_SCALE_DURATION_OFFSET) {
|
|
| 159 |
+ float rotateProgress = (renderProgress - START_SCALE_DURATION_OFFSET) / (END_TRIM_DURATION_OFFSET - START_SCALE_DURATION_OFFSET); |
|
| 160 |
+ mGroupRotation = ((FULL_GROUP_ROTATION / NUM_POINTS) * rotateProgress) + (FULL_GROUP_ROTATION * (mRotationCount / NUM_POINTS)); |
|
| 161 |
+ } |
|
| 162 |
+ |
|
| 163 |
+ if (Math.abs(mEndDegrees - mStartDegrees) > 0) {
|
|
| 164 |
+ mSwipeDegrees = mEndDegrees - mStartDegrees; |
|
| 165 |
+ } |
|
| 166 |
+ } |
|
| 167 |
+ |
|
| 168 |
+ @Override |
|
| 169 |
+ protected void setAlpha(int alpha) {
|
|
| 170 |
+ mPaint.setAlpha(alpha); |
|
| 171 |
+ } |
|
| 172 |
+ |
|
| 173 |
+ @Override |
|
| 174 |
+ protected void setColorFilter(ColorFilter cf) {
|
|
| 175 |
+ mPaint.setColorFilter(cf); |
|
| 176 |
+ } |
|
| 177 |
+ |
|
| 178 |
+ @Override |
|
| 179 |
+ protected void reset() {
|
|
| 180 |
+ resetOriginals(); |
|
| 181 |
+ } |
|
| 182 |
+ |
|
| 183 |
+ private void initStrokeInset(float width, float height) {
|
|
| 184 |
+ float minSize = Math.min(width, height); |
|
| 185 |
+ float strokeInset = minSize / 2.0f - mCenterRadius; |
|
| 186 |
+ float minStrokeInset = (float) Math.ceil(mStrokeWidth / 2.0f); |
|
| 187 |
+ mStrokeInset = strokeInset < minStrokeInset ? minStrokeInset : strokeInset; |
|
| 188 |
+ } |
|
| 189 |
+ |
|
| 190 |
+ private void storeOriginals() {
|
|
| 191 |
+ mOriginEndDegrees = mEndDegrees; |
|
| 192 |
+ mOriginStartDegrees = mEndDegrees; |
|
| 193 |
+ } |
|
| 194 |
+ |
|
| 195 |
+ private void resetOriginals() {
|
|
| 196 |
+ mOriginEndDegrees = 0; |
|
| 197 |
+ mOriginStartDegrees = 0; |
|
| 198 |
+ |
|
| 199 |
+ mEndDegrees = 0; |
|
| 200 |
+ mStartDegrees = 0; |
|
| 201 |
+ |
|
| 202 |
+ mSwipeDegrees = 1; |
|
| 203 |
+ } |
|
| 204 |
+ |
|
| 205 |
+ private void apply(Builder builder) {
|
|
| 206 |
+ this.mWidth = builder.mWidth > 0 ? builder.mWidth : this.mWidth; |
|
| 207 |
+ this.mHeight = builder.mHeight > 0 ? builder.mHeight : this.mHeight; |
|
| 208 |
+ this.mStrokeWidth = builder.mStrokeWidth > 0 ? builder.mStrokeWidth : this.mStrokeWidth; |
|
| 209 |
+ this.mCenterRadius = builder.mCenterRadius > 0 ? builder.mCenterRadius : this.mCenterRadius; |
|
| 210 |
+ |
|
| 211 |
+ this.mDuration = builder.mDuration > 0 ? builder.mDuration : this.mDuration; |
|
| 212 |
+ |
|
| 213 |
+ this.mColor = builder.mColor != 0 ? builder.mColor : this.mColor; |
|
| 214 |
+ |
|
| 215 |
+ this.mGearCount = builder.mGearCount > 0 ? builder.mGearCount : this.mGearCount; |
|
| 216 |
+ this.mGearSwipeDegrees = builder.mGearSwipeDegrees > 0 ? builder.mGearSwipeDegrees : this.mGearSwipeDegrees; |
|
| 217 |
+ |
|
| 218 |
+ setupPaint(); |
|
| 219 |
+ initStrokeInset(this.mWidth, this.mHeight); |
|
| 220 |
+ } |
|
| 221 |
+ |
|
| 222 |
+ public static class Builder {
|
|
| 223 |
+ private Context mContext; |
|
| 224 |
+ |
|
| 225 |
+ private int mWidth; |
|
| 226 |
+ private int mHeight; |
|
| 227 |
+ private int mStrokeWidth; |
|
| 228 |
+ private int mCenterRadius; |
|
| 229 |
+ |
|
| 230 |
+ private int mDuration; |
|
| 231 |
+ |
|
| 232 |
+ private int mColor; |
|
| 233 |
+ |
|
| 234 |
+ private int mGearCount; |
|
| 235 |
+ private int mGearSwipeDegrees; |
|
| 236 |
+ |
|
| 237 |
+ public Builder(Context mContext) {
|
|
| 238 |
+ this.mContext = mContext; |
|
| 239 |
+ } |
|
| 240 |
+ |
|
| 241 |
+ public Builder setWidth(int width) {
|
|
| 242 |
+ this.mWidth = width; |
|
| 243 |
+ return this; |
|
| 244 |
+ } |
|
| 245 |
+ |
|
| 246 |
+ public Builder setHeight(int height) {
|
|
| 247 |
+ this.mHeight = height; |
|
| 248 |
+ return this; |
|
| 249 |
+ } |
|
| 250 |
+ |
|
| 251 |
+ public Builder setStrokeWidth(int strokeWidth) {
|
|
| 252 |
+ this.mStrokeWidth = strokeWidth; |
|
| 253 |
+ return this; |
|
| 254 |
+ } |
|
| 255 |
+ |
|
| 256 |
+ public Builder setCenterRadius(int centerRadius) {
|
|
| 257 |
+ this.mCenterRadius = centerRadius; |
|
| 258 |
+ return this; |
|
| 259 |
+ } |
|
| 260 |
+ |
|
| 261 |
+ public Builder setDuration(int duration) {
|
|
| 262 |
+ this.mDuration = duration; |
|
| 263 |
+ return this; |
|
| 264 |
+ } |
|
| 265 |
+ |
|
| 266 |
+ public Builder setColor(int color) {
|
|
| 267 |
+ this.mColor = color; |
|
| 268 |
+ return this; |
|
| 269 |
+ } |
|
| 270 |
+ |
|
| 271 |
+ public Builder setGearCount(int gearCount) {
|
|
| 272 |
+ this.mGearCount = gearCount; |
|
| 273 |
+ return this; |
|
| 274 |
+ } |
|
| 275 |
+ |
|
| 276 |
+ public Builder setGearSwipeDegrees(@IntRange(from = 0, to = 360) int gearSwipeDegrees) {
|
|
| 277 |
+ this.mGearSwipeDegrees = gearSwipeDegrees; |
|
| 278 |
+ return this; |
|
| 279 |
+ } |
|
| 280 |
+ |
|
| 281 |
+ public GearLoadingRenderer build() {
|
|
| 282 |
+ GearLoadingRenderer loadingRenderer = new GearLoadingRenderer(mContext); |
|
| 283 |
+ loadingRenderer.apply(this); |
|
| 284 |
+ return loadingRenderer; |
|
| 285 |
+ } |
|
| 286 |
+ } |
|
| 287 |
+} |
@@ -121,4 +121,31 @@ |
||
| 121 | 121 |
<attr name="hasStickyHeaders" format="boolean" /> |
| 122 | 122 |
<attr name="isDrawingListUnderStickyHeader" format="boolean" /> |
| 123 | 123 |
</declare-styleable> |
| 124 |
+ |
|
| 125 |
+ <declare-styleable name="LoadingView"> |
|
| 126 |
+ <attr name="loading_renderer"> |
|
| 127 |
+ <!--circle rotate--> |
|
| 128 |
+ <enum name="MaterialLoadingRenderer" value="0"/> |
|
| 129 |
+ <enum name="LevelLoadingRenderer" value="1"/> |
|
| 130 |
+ <enum name="WhorlLoadingRenderer" value="2"/> |
|
| 131 |
+ <enum name="GearLoadingRenderer" value="3"/> |
|
| 132 |
+ <!--circle jump--> |
|
| 133 |
+ <enum name="SwapLoadingRenderer" value="4"/> |
|
| 134 |
+ <enum name="GuardLoadingRenderer" value="5"/> |
|
| 135 |
+ <enum name="DanceLoadingRenderer" value="6"/> |
|
| 136 |
+ <enum name="CollisionLoadingRenderer" value="7"/> |
|
| 137 |
+ <!--Scenery--> |
|
| 138 |
+ <enum name="DayNightLoadingRenderer" value="8"/> |
|
| 139 |
+ <enum name="ElectricFanLoadingRenderer" value="9"/> |
|
| 140 |
+ <!--Animal--> |
|
| 141 |
+ <enum name="FishLoadingRenderer" value="10"/> |
|
| 142 |
+ <enum name="GhostsEyeLoadingRenderer" value="11"/> |
|
| 143 |
+ <!--Goods--> |
|
| 144 |
+ <enum name="BalloonLoadingRenderer" value="12"/> |
|
| 145 |
+ <enum name="WaterBottleLoadingRenderer" value="13"/> |
|
| 146 |
+ <!--ShapeChange--> |
|
| 147 |
+ <enum name="CircleBroodLoadingRenderer" value="14"/> |
|
| 148 |
+ <enum name="CoolWaitLoadingRenderer" value="15"/> |
|
| 149 |
+ </attr> |
|
| 150 |
+ </declare-styleable> |
|
| 124 | 151 |
</resources> |